package pure.manager
{
		import flash.events.KeyboardEvent;

		/**
		 * 输入管理器
		 * ［-1:justRelease］［0:None］［1:Press］［2:justPress］
		 */
		public class InputManager
		{
			public function InputManager() {
				_lookup = new Object();
				_map = new Array(_total);
				_addAllKeys();
				StageProxy.stage.addEventListener(KeyboardEvent.KEY_DOWN, ____onKeyDown);
				StageProxy.stage.addEventListener(KeyboardEvent.KEY_UP, ____onKeyUp);
			}
			
			
			internal var _lookup:Object;
			internal var _map:Array;
			internal const _total:uint = 256;
			
			public var ESC:Boolean;
			public var F1:Boolean;
			public var F2:Boolean;
			public var F3:Boolean;
			public var F4:Boolean;
			public var F5:Boolean;
			public var F6:Boolean;
			public var F7:Boolean;
			public var F8:Boolean;
			public var F9:Boolean;
			public var F10:Boolean;
			public var F11:Boolean;
			public var F12:Boolean;
			public var ONE:Boolean;
			public var TWO:Boolean;
			public var THREE:Boolean;
			public var FOUR:Boolean;
			public var FIVE:Boolean;
			public var SIX:Boolean;
			public var SEVEN:Boolean;
			public var EIGHT:Boolean;
			public var NINE:Boolean;
			public var ZERO:Boolean;
			public var NUMPADONE:Boolean;
			public var NUMPADTWO:Boolean;
			public var NUMPADTHREE:Boolean;
			public var NUMPADFOUR:Boolean;
			public var NUMPADFIVE:Boolean;
			public var NUMPADSIX:Boolean;
			public var NUMPADSEVEN:Boolean;
			public var NUMPADEIGHT:Boolean;
			public var NUMPADNINE:Boolean;
			public var NUMPADZERO:Boolean;
			public var PAGEUP:Boolean;
			public var PAGEDOWN:Boolean;
			public var HOME:Boolean;
			public var END:Boolean;
			public var INSERT:Boolean;
			public var MINUS:Boolean;    // 减号
			public var PLUS:Boolean;    // 加号
			public var DELETE:Boolean;
			public var BACKSPACE:Boolean;    // 回车
			public var TAB:Boolean;
			public var Q:Boolean;
			public var W:Boolean;
			public var E:Boolean;
			public var R:Boolean;
			public var T:Boolean;
			public var Y:Boolean;
			public var U:Boolean;
			public var I:Boolean;
			public var O:Boolean;
			public var P:Boolean;
			public var LBRACKET:Boolean;    // [
			public var RBRACKET:Boolean;    // ]
			public var BACKSLASH:Boolean;    // "\"
			public var CAPSLOCK:Boolean;
			public var A:Boolean;
			public var S:Boolean;
			public var D:Boolean;
			public var F:Boolean;
			public var G:Boolean;
			public var H:Boolean;
			public var J:Boolean;
			public var K:Boolean;
			public var L:Boolean;
			public var SEMICOLON:Boolean;    // ;
			public var QUOTE:Boolean;    // ""
			public var ENTER:Boolean;
			public var SHIFT:Boolean;
			public var Z:Boolean;
			public var X:Boolean;
			public var C:Boolean;
			public var V:Boolean;
			public var B:Boolean;
			public var N:Boolean;
			public var M:Boolean;
			public var COMMA:Boolean;    // ,
			public var PERIOD:Boolean;    // .
			public var SLASH:Boolean;    // /
			public var CONTROL:Boolean;
			public var ALT:Boolean;
			public var SPACE:Boolean;
			public var UP:Boolean;
			public var DOWN:Boolean;
			public var LEFT:Boolean;
			public var RIGHT:Boolean;
			
			
			// 按下
			public function pressed(key:String):Boolean { return this[key]; }
			
			// 刚按下（类似MouseDown）
			public function justPressed(key:String):Boolean { return _map[_lookup[key]].current == 2; }
			
			// 刚弹起（类似MouseUp）
			public function justReleased(key:String):Boolean { return _map[_lookup[key]].current == -1; }
			
			// 是否按下任何按键
			public function any():Boolean {
				var i:uint = 0;
				while(i < _total) {
					var o:Object = _map[i++];
					if ((o != null) && (o.current > 0)) return true;
				}
				return false;
			}
			
			// 重置
			public function reset():void {
				var i:uint = 0;
				while(i < _total) {
					var o:Object = _map[i++];
					if(o == null) continue;
					this[o.name] = false;
					o.current = 0;
					o.nm = 0;
				}
			}
			
			/**
			 * If any keys are not "released" (0),
			 * this function will return an array indicating
			 * which keys are pressed and what state they are in.
			 * 
			 * @return	An array of key state data.  Null if there is no data.
			 */
			public function record():Array
			{
				var data:Array = null;
				var i:uint = 0;
				while(i < _total)
				{
					var o:Object = _map[i++];
					if((o == null) || (o.current == 0))
						continue;
					if(data == null)
						data = new Array();
					data.push({code:i-1,value:o.current});
				}
				return data;
			}
			
			/**
			 * Part of the keystroke recording system.
			 * Takes data about key presses and sets it into array.
			 * 
			 * @param	Record	Array of data about key states.
			 */
			public function playback(Record:Array):void
			{
				var i:uint = 0;
				var l:uint = Record.length;
				var o:Object;
				var o2:Object;
				while(i < l)
				{
					o = Record[i++];
					o2 = _map[o.code];
					o2.current = o.value;
					if(o.value > 0)
						this[o2.name] = true;
				}
			}
			
			// 单例
			public static function get instance():InputManager {
				if (!_instance) _instance = new InputManager();
				return _instance;
			}
			private static var _instance:InputManager;
			
			
			
			
			/* ----------------------------------------------------------------------------------------------------------------
			* ★★★★★★★★★★★★★★★★★★★★★  private  ★★★★★★★★★★★★★★★★★★★★★
			* ----------------------------------------------------------------------------------------------------------------
			*/
			
			
			
			/**
			 * 更新
			 * 按下/弹起键后，
			 * （本帧）更新上一帧按键状态
			 * （次帧）根据上一帧按键状态，判断当前按键状态
			 */
			public function update():void {
				var i:uint = 0;
				while(i < _total) {
					var o:Object = _map[i++];
					if (o == null) continue;
					
					// justRelease
					if ((o.last == -1) && (o.current == -1)) {
						o.current = 0;
					}
						
						// justPress
					else if ((o.last == 2) && (o.current == 2)) {
						o.current = 1;
					}
					
					// 更新上一帧按键状态
					o.last = o.current;
				}
			}
			
			protected function _addAllKeys():void {
				// A-Z
				var i:uint = 65;
				while(i <= 90) _addKey(String.fromCharCode(i),i++);
				
				//NUMBERS
				i = 48;
				_addKey("ZERO",i++);
				_addKey("ONE",i++);
				_addKey("TWO",i++);
				_addKey("THREE",i++);
				_addKey("FOUR",i++);
				_addKey("FIVE",i++);
				_addKey("SIX",i++);
				_addKey("SEVEN",i++);
				_addKey("EIGHT",i++);
				_addKey("NINE",i++);
				i = 96;
				_addKey("NUMPADZERO",i++);
				_addKey("NUMPADONE",i++);
				_addKey("NUMPADTWO",i++);
				_addKey("NUMPADTHREE",i++);
				_addKey("NUMPADFOUR",i++);
				_addKey("NUMPADFIVE",i++);
				_addKey("NUMPADSIX",i++);
				_addKey("NUMPADSEVEN",i++);
				_addKey("NUMPADEIGHT",i++);
				_addKey("NUMPADNINE",i++);
				_addKey("PAGEUP", 33);
				_addKey("PAGEDOWN", 34);
				_addKey("HOME", 36);
				_addKey("END", 35);
				_addKey("INSERT", 45);
				
				//FUNCTION KEYS
				i = 1;
				while(i <= 12) _addKey("F"+i,111+(i++));
				
				//SPECIAL KEYS + PUNCTUATION
				_addKey("ESC",27);
				_addKey("MINUS",189);
				_addKey("PLUS",187);
				_addKey("DELETE",46);
				_addKey("BACKSPACE",8);
				_addKey("LBRACKET",219);
				_addKey("RBRACKET",221);
				_addKey("BACKSLASH",220);
				_addKey("CAPSLOCK",20);
				_addKey("SEMICOLON",186);
				_addKey("QUOTE",222);
				_addKey("ENTER",13);
				_addKey("SHIFT",16);
				_addKey("COMMA",188);
				_addKey("PERIOD",190);
				_addKey("SLASH",191);
				_addKey("CONTROL",17);
				_addKey("ALT",18);
				_addKey("SPACE",32);
				_addKey("UP",38);
				_addKey("DOWN",40);
				_addKey("LEFT",37);
				_addKey("RIGHT",39);
				_addKey("TAB", 9);
			}
			
			/**
			 * 加入按键
			 * @param keyName
			 * @param keyCode
			 */
			protected function _addKey(keyName:String,keyCode:uint):void {
				_lookup[keyName] = keyCode;
				_map[keyCode] = { name: keyName, current: 0, last: 0 };
			}
			
			// ［-1:justRelease］［0:Release］［1:Press］［2:justPress］
			protected function ____onKeyDown(e:KeyboardEvent):void {
				e.updateAfterEvent();
				var object:Object = _map[e.keyCode];
				if (object == null) return;
				
				// current > 0:按住
				if (object.current > 0) {
					object.current = 1;
				}
					
					// current <= 0:未按
				else {
					object.current = 2;
				}
				this[object.name] = true;
			}
			
			protected function ____onKeyUp(e:KeyboardEvent):void {
				e.updateAfterEvent();
				var object:Object = _map[e.keyCode];
				if(object == null) return;
				if (object.current > 0) {
					object.current = -1;
				}
				else {
					object.current = 0;
				}
				this[object.name] = false;
			}
		}
	}
